/*
 * BorderLayout.java  0.4.0 / Oct 24, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
package com.cute4j.swing.layouts;

import com.cute4j.swing.Component;
import com.cute4j.swing.Container;
import com.cute4j.swing.graphics.Dimension;
import com.cute4j.swing.graphics.Insets;

/**
 * Border Layout.
 *
 * @author Slobodan Vrkacevic
 * @version 0.4.0
 */
public class BorderLayout implements LayoutManager {

// Public Static Fields. -------------------------------------------------------

  /**
   * <tt>North</tt> layout constraints (the value is {@value}).
   */
  public static final String NORTH = "North";

  /**
   * <tt>South</tt> layout constraints (the value is {@value}).
   */
  public static final String SOUTH = "South";

  /**
   * <tt>East</tt> layout constraints (the value is {@value}).
   */
  public static final String EAST = "East";

  /**
   * <tt>West</tt> layout constraints (the value is {@value}).
   */
  public static final String WEST = "West";

  /**
   * <tt>Center</tt> layout constraints (the value is {@value}).
   */
  public static final String CENTER = "Center";

// Private Fields. -------------------------------------------------------------

  private int hgap;
  private int vgap;
  private Component north;
  private Component west;
  private Component east;
  private Component south;
  private Component center;

// Public Constructors. --------------------------------------------------------

  /**
   * Constructs new BorderLayout object.
   */
  public BorderLayout() {
    // empty body
  }

  /**
   * Constructs new BorderLayout object.
   *
   * @param hgap the horizontal gap.
   * @param vgap the vertical gap.
   */
  public BorderLayout(int hgap, int vgap) {
    this.hgap = hgap;
    this.vgap = vgap;
  }

// Public Methods. -------------------------------------------------------------

  /**
   * Returns the horizontal gap between components.
   *
   * @return the horizontal gap between components
   */
  public int getHgap() {
    return hgap;
  }

  /**
   * Sets the horizontal gap between components.
   *
   * @param hgap the horizontal gap between components
   */
  public void setHgap(int hgap) {
    this.hgap = hgap;
  }

  /**
   * Returns the vertical gap between components.
   *
   * @return the vertical gap between components
   */
  public int getVgap() {
    return vgap;
  }

  /**
   * Sets the vertical gap between components.
   *
   * @param vgap the vertical gap between components
   */
  public void setVgap(int vgap) {
    this.vgap = vgap;
  }

// LayoutManager Interface Implementation. -------------------------------------

  /**
   * {@inheritDoc}
   */
  public void addLayoutComponent(Component component,
                                 Object constraints) { // NOPMD
    if (constraints == null) {
      constraints = CENTER;
    }
    if (CENTER.equals(constraints)) {
      center = component;
      Container parent = component.getParent();
      if (parent != null) {
        Insets insets = parent.getInsets();
        int top = insets.getTop();
        int bottom = parent.getHeight() - insets.getBottom();
        int left = insets.getLeft();
        int right = parent.getWidth() - insets.getRight();
        component.setBounds(left, top, right - left, bottom - top);
      }
    } else if (NORTH.equals(constraints)) {
      north = component;
    } else if (SOUTH.equals(constraints)) {
      south = component;
    } else if (EAST.equals(constraints)) {
      east = component;
    } else if (WEST.equals(constraints)) {
      west = component;
    } else {
      throw new IllegalArgumentException("Unknown constraints: " + constraints);
    }
  }

  /**
   * {@inheritDoc}
   */
  public void removeLayoutComponent(Component component) {
    if (component == center) { // NOPMD
      center = null;
    } else if (component == north) { // NOPMD
      north = null;
    } else if (component == south) { // NOPMD
      south = null;
    } else if (component == east) { // NOPMD
      east = null;
    } else if (component == west) { // NOPMD
      west = null;
    }
  }

  /**
   * {@inheritDoc}
   */
  public Dimension preferredLayoutSize(Container target) { // NOPMD
    int width = 0;
    int height = 0;
    if (east != null) {
      Dimension d = east.getPreferredSize();
      width += d.getWidth() + hgap;
      if (d.getHeight() > 0) {
        height = d.getHeight();
      }
    }
    if (west != null) {
      Dimension d = west.getPreferredSize();
      width += d.getWidth() + hgap;
      if (d.getHeight() > height) {
        height = d.getHeight();
      }
    }
    if (center != null) {
      Dimension d = center.getPreferredSize();
      width += d.getWidth();
      if (d.getHeight() > height) {
        height = d.getHeight();
      }
    }
    if (north != null) {
      Dimension d = north.getPreferredSize();
      if (d.getWidth() > width) {
        width = d.getWidth();
      }
      height += d.getHeight() + vgap;
    }
    if (south != null) {
      Dimension d = south.getPreferredSize();
      if (d.getWidth() > width) {
        width = d.getWidth();
      }
      height += d.getHeight() + vgap;
    }
    Insets insets = target.getInsets();
    width += insets.getLeft() + insets.getRight();
    height += insets.getTop() + insets.getBottom();
    return new Dimension(width, height);
  }

  /**
   * {@inheritDoc}
   */
  public Dimension maximumLayoutSize(Container target) {
    return Dimension.INFINITE_DIMESNION;
  }

  /**
   * {@inheritDoc}
   */
  public Dimension minimumLayoutSize(Container target) {
    int width = 0;
    int height = 0;
    if (east != null) {
      Dimension d = east.getMinimumSize();
      width += d.getWidth() + hgap;
      if (d.getHeight() > 0) {
        height = d.getHeight();
      }
    }
    if (west != null) {
      Dimension d = west.getMinimumSize();
      width += d.getWidth() + hgap;
      if (d.getHeight() > height) {
        height = d.getHeight();
      }
    }
    if (center != null) {
      Dimension d = center.getMinimumSize();
      width += d.getWidth();
      if (d.getHeight() > height) {
        height = d.getHeight();
      }
    }
    if (north != null) {
      Dimension d = north.getMinimumSize();
      if (d.getWidth() > width) {
        width = d.getWidth();
      }
      height += d.getHeight() + vgap;
    }
    if (south != null) {
      Dimension d = south.getMinimumSize();
      if (d.getWidth() > width) {
        width = d.getWidth();
      }
      height += d.getHeight() + vgap;
    }
    Insets insets = target.getInsets();
    width += insets.getLeft() + insets.getRight();
    height += insets.getTop() + insets.getBottom();
    return new Dimension(width, height);
  }

  /**
   * {@inheritDoc}
   */
  public void layoutContainer(Container target) {
    Insets insets = target.getInsets();
    int top = insets.getTop();
    int bottom = target.getHeight() - insets.getBottom();
    int left = insets.getLeft();
    int right = target.getWidth() - insets.getRight();
    if ((north != null) && north.isDisplayable()) {
      north.setSize(right - left, north.getHeight());
      Dimension d = north.getPreferredSize();
      north.setBounds(left, top, right - left, d.getHeight());
      top += d.getHeight() + vgap;
    }
    if ((south != null) && south.isDisplayable()) {
      south.setSize(right - left, south.getHeight());
      Dimension d = south.getPreferredSize();
      south.setBounds(left, bottom - d.getHeight(), right - left,
                      d.getHeight());
      bottom -= d.getHeight() + vgap;
    }
    if ((east != null) && east.isDisplayable()) {
      east.setSize(east.getWidth(), bottom - top);
      Dimension d = east.getPreferredSize();
      east.setBounds(right - d.getWidth(), top, d.getWidth(), bottom - top);
      right -= d.getWidth() + hgap;
    }
    if ((west != null) && west.isDisplayable()) {
      west.setSize(west.getWidth(), bottom - top);
      Dimension d = west.getPreferredSize();
      west.setBounds(left, top, d.getWidth(), bottom - top);
      left += d.getWidth() + hgap;
    }
    if (center != null) {
      center.setBounds(left, top, right - left, bottom - top);
    }
  }

  /**
   * {@inheritDoc}
   */
  public void invalidateLayout(Container target) {
    // empty method body
  }

// Overridden Methods. ---------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  public String toString() {
    return getClass().getName() + "[hgap=" + hgap + ", vgap=" + vgap + "]";
  }

}
